package com.umeox.watch.moto.dataservice.observer;

import android.app.AppOpsManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.provider.Telephony;

import com.umeox.moto.common.log.Logger;
import com.umeox.moto.common.utils.StringUtils;
import com.umeox.watch.moto.dataservice.base.BaseApp;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class SMSContentObserver extends ContentObserver implements Runnable {

    private static final int OP_WRITE_SMS = 15;
    private final Object mLock;
    private final BlockingQueue<String> queue;
    private Context mContext;
    private Handler mHandler;

    private SMSContentObserver(Context context, Handler handler) {
        super(handler);
        mContext = context;
        mHandler = handler;
        mLock = new Object();
        queue = new LinkedBlockingQueue<String>();
    }

    public static SMSContentObserver getInstance() {
        return Holder.INSTANCE;
    }

    private int getUid() {
        try {
            return mContext.getPackageManager().getApplicationInfo(
                    mContext.getPackageName(), PackageManager.GET_META_DATA).uid;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            return 0;
        }
    }

    public void registerSmsContentObserver() {
        unregisterSmsContentObserver();
        mContext.getContentResolver().registerContentObserver(Telephony.Sms.CONTENT_URI, true, Holder.INSTANCE);
    }

    private void unregisterSmsContentObserver() {
        try {
            mContext.getContentResolver().unregisterContentObserver(Holder.INSTANCE);
        } catch (Exception e) {
        }
    }

    private boolean isWriteEnabled() {
        int uid = getUid();
        Object opRes = checkOp(OP_WRITE_SMS, uid);

        if (opRes instanceof Integer) {
            return (Integer) opRes == AppOpsManager.MODE_ALLOWED;
        }
        return false;
    }

    private boolean setWriteEnabled(boolean enabled) {
        int uid = getUid();
        int mode = enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
        return setMode(OP_WRITE_SMS, uid, mode);
    }

    private Object checkOp(int code, int uid) {
        AppOpsManager appOpsManager = (AppOpsManager) mContext
                .getSystemService(Context.APP_OPS_SERVICE);
        Class appOpsManagerClass = appOpsManager.getClass();

        try {
            Class[] types = new Class[3];
            types[0] = Integer.TYPE;
            types[1] = Integer.TYPE;
            types[2] = String.class;
            Method checkOpMethod = appOpsManagerClass.getMethod("checkOp", types);

            Object[] args = new Object[3];
            args[0] = code;
            args[1] = uid;
            args[2] = mContext.getPackageName();

            return checkOpMethod.invoke(appOpsManager, args);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    private boolean setMode(int code, int uid, int mode) {
        AppOpsManager appOpsManager = (AppOpsManager) mContext
                .getSystemService(Context.APP_OPS_SERVICE);
        Class appOpsManagerClass = appOpsManager.getClass();

        try {
            Class[] types = new Class[4];
            types[0] = Integer.TYPE;
            types[1] = Integer.TYPE;
            types[2] = String.class;
            types[3] = Integer.TYPE;
            Method setModeMethod = appOpsManagerClass.getMethod("setMode", types);

            Object[] args = new Object[4];
            args[0] = code;
            args[1] = uid;
            args[2] = mContext.getPackageName();
            args[3] = mode;
            setModeMethod.invoke(appOpsManager, args);

            return true;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 当所监听的Uri发生改变时，就会回调此方法
     *
     * @param selfChange 此值意义不大 一般情况下该回调值false
     */
    @Override
    public void onChange(boolean selfChange) {
        Logger.w("the sms table has changed");
        //查询收件箱里未读的内容
        Uri inBoxUri = Telephony.Sms.Inbox.CONTENT_URI;
        String selection = Telephony.BaseMmsColumns.READ + "=?";
        String[] selectionArgs = new String[]{"0"};
        String sortOrder = Telephony.BaseMmsColumns.DATE + " desc";
        Cursor c = mContext.getContentResolver().query(inBoxUri, null, selection, selectionArgs, sortOrder);
        if (c != null) {
            synchronized (mLock) {
                Logger.w("the number of in is " + c.getCount());
                //循环遍历
                while (c.moveToNext()) {
                    StringBuilder sb = new StringBuilder();
                    String address = c.getString(c.getColumnIndex("address"));
                    String body = c.getString(c.getColumnIndex("body"));
                    sb.append("发件人手机号码: ").append(address).append("信息内容: ").append(body).append("\n");
                    Logger.w("新的短消息->" + sb.toString());
                    queue.offer(body);
                }
                c.close();
                //标记所有短信已读
                updateSmsReadState();
                //消息列队完成，开始调用服务发送消息
                mHandler.post(this);
            }
        } else {
            Logger.w("the sms table has changed, but inbox is null");
        }
    }

    private void updateSmsReadState() {
        if (!isWriteEnabled()) {
            setWriteEnabled(true);
        }

        ContentResolver contentResolver = mContext.getContentResolver();
        ContentValues values = new ContentValues();
        values.put(Telephony.BaseMmsColumns.READ, 1);
        String selection = Telephony.BaseMmsColumns.READ + "=?";
        String[] selectionArgs = new String[]{"0"};
        int rc1 = contentResolver.update(Telephony.Sms.CONTENT_URI, values, selection, selectionArgs);
        Logger.w("标记短信已读->" + rc1);
    }

    @Override
    public void run() {
        String body = queue.poll();
        if (!StringUtils.isEmpty(body)) {
            Logger.w(String.format(Locale.getDefault(), "转发短信[%s]给管理员", body));
            //MessageService.sendMessage(mContext, body, System.currentTimeMillis());
        }
    }

    private static class Holder {
        private static SMSContentObserver INSTANCE = new SMSContentObserver(BaseApp.getInstance(), new Handler());
    }
}
